/*
 * Breach: session.js
 *
 * Copyright (c) 2014, Stanislas Polu. All rights reserved.
 *
 * @author: spolu
 *
 * @log:
 * - 2014-05-14 spolu   [GiG.fs 0.2.x] local only
 * - 2014-04-11 spolu   GiG.fs Integration
 * - 2014-01-17 spolu   New Init/RunModules API
 * - 2013-11-14 spolu   FMA refactoring
 * - 2013-10-21 spolu   Cookie Store integration for v0.1
 * - 2013-09-05 spolu   Fix exo_browser/#56
 * - 2013-08-12 spolu   Creation
 */
"use strict"

var events = require('events');
var async = require('async');
var path = require('path');
var mkdirp = require('mkdirp');

var api = require('exo_browser');
var common = require('./common.js');

// ## session
//
// The session takes three arguments. 
//  - `session_id` generated by the session_manager
//  - `gig` to use as data store for the session. This `gig` can be in-memory.
//     If `null`, an in-memory gig is created.
//  - `off_the_record` whether the browser is authorised to cache data locally.
//
// ```
// @emits `ready`
// @spec { session_id, gig, off_the_record }
// ```
var session = function(spec, my) {
  var _super = {};
  my = my || {};
  spec = spec || {};

  my.session_id = spec.session_id || 'NO_SESSION_ID';

  my.off_the_record = spec.off_the_record || false;
  my.data_path = my.off_the_record ? null : 
    path.join(api.data_path('breach'), 'sessions', my.session_id);

  my.gig = spec.gig || require('gig.fs').gig({
    local_table: {
      'core': [ { storage_path: null } ],
      'modules': [ { storage_path: null } ]
    }
  });
  my.core_module = null;
  my.module_manager = null;

  //
  // _public_
  //
  var init;          /* init(cb_); */
  var kill;          /* kill(cb_); */

  var run_modules;   /* run_modules(cb_); */

  //
  // _private_
  //

  //
  // #### _that_
  //
  var that = new events.EventEmitter();

  /****************************************************************************/
  /* PUBLIC METHODS */
  /****************************************************************************/
  // ### init
  // 
  // Initialializes this session. The initialization must not go on network as
  // we need to display as fast as possible the session window (exo_browser)
  // and show the blank loading page.
  // ```
  // @cb_ {function(err, session)} asynchronous callback
  // ```
  init = function(cb_) {
    async.series([
      function(cb_) {
        if(!my.off_the_record) {
          mkdirp(my.data_path, cb_);
        }
        else {
          return cb_();
        }
      },
      function(cb_) {
        my.module_manager = require('./module_manager.js').module_manager({
          session: that
        });
        my.module_manager.init(cb_);
      }
    ], function(err) {
      return cb_(err, that);
    });
  };

  // ### run_modules
  // 
  // Starts the core_module and all installed modules
  // ```
  // @cb_ {function(err)} asynchronous callback
  // ```
  run_modules = function(cb_) {
    async.series([
      function(cb_) {
        my.core_module = require('./core_module.js').core_module({
          session: that
        });
        my.core_module.init(cb_);
      },
      function(cb_) {
        my.module_manager.list(function(err, modules) {
          if(err) {
            return cb_(err);
          }
          async.each(modules, function(m, cb_) {
            my.module_manager.run_module(m.path, cb_);
          }, cb_);
        });
      },
      function(cb_) {
        that.emit('ready');
        return cb_();
      }
    ], cb_);
  };

  // ### kill
  //
  // Kills this session as well as the underlying exo_browser
  // ```
  // @cb_ {function(err)} asynchronous callback
  // ```
  kill = function(cb_) {
    common.log.out('[session] {' + my.session_id + '} KILL');
    async.series([
      function(cb_) {
        my.module_manager.kill(cb_);
      },
      function(cb_) {
        if(my.core_module) { 
          my.core_module.kill(cb_);
        }
        else {
          return cb_();
        }
      },
      function(cb_) {
        setTimeout(function() {
          that.emit('kill');
        });
        return cb_();
      }
    ], cb_);
  };
  
  common.method(that, 'init', init, _super);
  common.method(that, 'kill', kill, _super);

  common.method(that, 'run_modules', run_modules, _super);

  common.getter(that, 'session_id', my, 'session_id');
  common.getter(that, 'gig', my, 'gig');
  common.getter(that, 'off_the_record', my, 'off_the_record');
  common.getter(that, 'data_path', my, 'data_path');

  common.getter(that, 'module_manager', my, 'module_manager');

  return that;
};

exports.session = session;
